package com.zqq.demo.camera;

import android.annotation.SuppressLint;
import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;


import com.zqq.base.utils.LogUtils;
import com.zqq.demo.utils.FileUtils;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;

public class H264Saver extends Thread {

    private int mWidth = 1280;
    private int mHeight = 720;
    private Context mContext;
    private MediaCodec mMediaCodec;

    private boolean isStart = false;
    private String currentFilePath;
    private String filePath;
    private int channelId;
    private MediaFormat mediaFormat;
    private MediaMuxer mMuxer;
    private int mTrackIndex;

    public H264Saver(Context context, int mWidth, int mHeight,int channelId) {
        mContext = context;
        this.mWidth = mWidth;
        this.mHeight = mHeight;
        this.channelId = channelId;
    }

    long mPresentTimeUs;
    public void init() {
        int framerate = 20;
        int bitrate = 500 * 1024;
        if (mWidth == 1280) {
            bitrate = 500 * 1024;
            LogUtils.i("bl_h264_saver",  "startMediaCodec, 720p,  bitrate=" + (bitrate / 1024) + "k");
        } else if (mWidth == 1920) {
            bitrate = 900 * 1024;
            LogUtils.i("bl_h264_saver", "startMediaCodec, 1080p,  bitrate=" + (bitrate / 1024) + "k");
        }

        mPresentTimeUs = System.nanoTime() / 1000;
        LogUtils.i("bl_h264_saver","mWidth>>"+mWidth);
        LogUtils.i("bl_h264_saver","mHeight>>"+mHeight);

        try {
//            mMediaCodec = MediaCodec.createByCodecName(debugger.getEncoderName());
            mMediaCodec = MediaCodec.createEncoderByType("video/avc");
            mediaFormat = MediaFormat.createVideoFormat("video/avc", mWidth, mHeight);
            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
//        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, debugger.getEncoderColorFormat());
            mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 21);
//            mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
            mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mMediaCodec.start();

//            Bundle params = new Bundle();
//            params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
//            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//                mMediaCodec.setParameters(params);
//            }

//            inputBuffers = mMediaCodec.getInputBuffers();
//            outputBuffers = mMediaCodec.getOutputBuffers();
            start(); //启动自己
            isStart = true;
        } catch (IOException e) {
            e.printStackTrace();
        }

        setNewPath();
    }

    private boolean mMuxerStarted;
    public void onVideo(byte[] data) {

         if (!isStart || filePath == null) return;

////        inputBuffers = mMediaCodec.getInputBuffers();
////        outputBuffers = mMediaCodec.getOutputBuffers();
//        int bufferIndex = mMediaCodec.dequeueInputBuffer(0);
//        //MainService.mEasyPusher.addwatermarkScale(data, Scaler, data.length,Constants.RECORD_VIDEO_WIDTH,Constants.RECORD_VIDEO_HEIGHT,Constants.UPLOAD_VIDEO_WIDTH,Constants.UPLOAD_VIDEO_HEIGHT);
//        if (bufferIndex >= 0) {
//            ByteBuffer buffer = null;
//            buffer = inputBuffers[bufferIndex];
////		    buffer.clear();
//            buffer.put(data);
//            buffer.clear();
//            long pts = System.nanoTime() / 1000 - mPresentTimeUs;
//            mMediaCodec.queueInputBuffer(bufferIndex, 0, data.length, pts, 0);
//        }

        try {
            ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();
            int inputBufferIndex = mMediaCodec.dequeueInputBuffer(10000);
            if (inputBufferIndex >= 0) {
                ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                inputBuffer.clear();
                inputBuffer.put(data);
                mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length,
                        System.nanoTime() / 1000, 0);
            }

            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 10000);
            while (outputBufferIndex >= 0) {
                ByteBuffer outputBuffer = mMediaCodec.getOutputBuffer(outputBufferIndex);
                byte[] outData = new byte[bufferInfo.size];
                outputBuffer.get(outData);

                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                    setNewPath();
                    if (!mMuxerStarted) {
                        MediaFormat format = mMediaCodec.getOutputFormat();
                        mTrackIndex = mMuxer.addTrack(format);
                        mMuxer.start();
                        mMuxerStarted = true;
                    }
                } else {
                    if(mMuxerStarted) {
                        mMuxer.writeSampleData(mTrackIndex, outputBuffer, bufferInfo);
                    }
                }

                mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        super.run();
//
//        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
//        int outputBufferIndex = 0;
//        byte[] mPpsSps = new byte[0];
//        LogUtils.i("bl_h264_saver", "isStart>>" + isStart);
//        do {
//            outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 30000);
//            if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
//                //no output available yet
//            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
//                //not expected for an encoder
//            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
//               /*EasyMuxer muxer = mMuxer;
//                 if(muxer != null) {
//                    //should happen before receiving buffers, and should only happen once
//                    MediaFormat newFormat = mMediaCodec.getOutputFormat();
//                    muxer.addTrack(newFormat, true);
//                }*/
//            } else if (outputBufferIndex < 0) {
//                // let's ignore it
//            } else {
//                ByteBuffer outputBuffer;
//                outputBuffer = outputBuffers[outputBufferIndex];
////                Muxer muxer = mMuxer;
////                if (muxer != null) {
////                    muxer.pumpStream(outputBuffer, bufferInfo, true);
////                }
//                LogUtils.i("bl_h264_saver","mediaMuxerHelper>>"+mediaMuxerHelper);
//                if(mediaMuxerHelper != null){
//                    setNewPath();
//                    if(!filePath.equals(currentFilePath)){
//                        currentFilePath = filePath;
//                    }
//                    mediaMuxerHelper.writeVideoData(outputBuffer,bufferInfo);
//                }else{
//                    boolean sync = false;
//                    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {// sps
//                        sync = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
//                        if (!sync) {
//                            byte[] temp = new byte[bufferInfo.size];
//                            outputBuffer.get(temp);
//                            mPpsSps = temp;
//                            mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
//                            continue;
//                        } else {
//                            mPpsSps = new byte[0];
//                        }
//                    }
//                    sync |= (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0;
//
//                    if (sync) {
//
//                        LogUtils.i("bl_h264_saver","关键帧>>" );
//
////                    System.arraycopy(mPpsSps, 0, h264, 0, mPpsSps.length);
////                    outputBuffer.get(h264, mPpsSps.length, bufferInfo.size);
//                        setNewPath();
//                        if(!filePath.equals(currentFilePath)){
//                            currentFilePath = filePath;
//                            if(channelId != 0) {
//                                FileUtils.writeFile(currentFilePath, mPpsSps);
//                            }
//                        }
//
//                        byte[] frameData = new byte[bufferInfo.size];
//                        outputBuffer.position(bufferInfo.offset);
//                        outputBuffer.get(frameData, 0, bufferInfo.size);
//
//
////                    LogUtils.i("bl_h264_saver", "mPpsSps>>" + HexStringUtil.bytes2HexString(mPpsSps));
////                    LogUtils.i("bl_h264_saver", "h2641111111>>" + HexStringUtil.bytes2HexString(frameData));
//                        if(channelId != 0){
//                            FileUtils.writeFile(currentFilePath,frameData);
//                        }
//
//                    } else {
//                        byte[] frameData = new byte[bufferInfo.size];
//                        outputBuffer.position(bufferInfo.offset);
//                        outputBuffer.get(frameData, 0, bufferInfo.size);
////                    LogUtils.i("bl_h264_saver", "h26422222222>>" + HexStringUtil.bytes2HexString(frameData));
//                        if(channelId != 0) {
//                            FileUtils.writeFile(currentFilePath, frameData);
//                        }
//                    }
//                }
//
//                mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
//            }
//        }
//        while (isStart);
    }


    public void onVideoStop() {

        AudioRecordManager.getInstance(mContext).stopAudio();

        do {
            isStart = false;
            try {
                join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } while (isAlive());

        try {
            Thread.sleep(100);
        } catch (Exception e) {
        }
        if (mMediaCodec != null) {
            stopMediaCodec();
            mMediaCodec = null;
        }
    }


    /**
     * 停止编码并释放编码资源占用
     */
    private void stopMediaCodec() {
        mMediaCodec.stop();
        mMediaCodec.release();
    }

    private long startTime = 0;
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
    private SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd");
    private void setNewPath(){
        long currentTimeMillis = SystemClock.elapsedRealtime();
        LogUtils.i("bl_h264_saver"+channelId,"currentTimeMillis>>"+currentTimeMillis);
        LogUtils.i("bl_h264_saver"+channelId,"currentTimeMillis - startTime>>"+(currentTimeMillis - startTime));
        if(currentTimeMillis - startTime < 5*60*1000){
            return;
        }
        startTime = currentTimeMillis;

        String timeStamp = simpleDateFormat.format(new Date());
        String timeStamp2 = simpleDateFormat2.format(new Date());
        String recPath = mContext.getCacheDir()+"/videos" ;//外置卡
        if(channelId==0){
            filePath = recPath+ "/" +timeStamp2+"/" + channelId + "/" + timeStamp + ".mp4";
            try {
                mMuxerStarted = false;
                mMuxer = new MediaMuxer(filePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            filePath = recPath+ "/" +timeStamp2+"/" + channelId + "/" + timeStamp + ".h264";
        }
        LogUtils.i("bl_h264_saver", " filepath:" + filePath);
        File dirs2 = new File(recPath+ "/" +timeStamp2+"/" + channelId + "/");
        if (!dirs2.exists()) dirs2.mkdirs();
    }
}
